package kr.co.bnsmedia.touchconfig;

import java.nio.ByteBuffer;

import android.app.Application;
import android.os.Message;
import android.util.Log;

public class MyApp extends Application {

	private static final String TAG = "usbhid";
	public static void log(String log) {
		Log.i(TAG, log);
	}

	public static final int HANDLER_RESULT = 1000;
	public static final int HANDLER_EVENT = 1001;

	private static WeakRefHandler mHandler = null;
	private static ByteBuffer mWriteBuffer = ByteBuffer.allocate(g.usbhid.PKT_MAX_LEN);

	public static byte[] mDeviceState = new byte[g.device.MAX_COUNT];
	public static PacketVersion[] mDeviceVersion = new PacketVersion[g.device.MAX_COUNT];
	public static PacketTouchConfig mTouchConfig = new PacketTouchConfig();
	public static PacketCameraConfig[] mCameraConfig = new PacketCameraConfig[g.device.MAX_CAMERA];

	public int start() {
		return usbhidStart();
	}

	public void stop() {
		usbhidStop();
	}

	public void setHandler(WeakRefHandler handler) {
		mHandler = handler;
	}

	public int wirtePacket(int aCommand, int aDevice, int aDataLen, byte[] aData) {
		mWriteBuffer.put(g.usbhid.PKT_POS_RID, (byte)g.usbhid.PKT_REPORT_ID);
		mWriteBuffer.put(g.usbhid.PKT_POS_CMD, (byte)aCommand);
		mWriteBuffer.put(g.usbhid.PKT_POS_DEV, (byte)aDevice);
		mWriteBuffer.put(g.usbhid.PKT_POS_DLEN, (byte)aDataLen);
		for (int i=0; i<aDataLen; i++) {
			mWriteBuffer.put((g.usbhid.PKT_POS_DATA + i), aData[i]);
		}

		return usbhidWrite(g.usbhid.PKT_MAX_LEN, mWriteBuffer.array());
	}
	public int wirtePacket(int aCommand, int aDevice) {
		return wirtePacket(aCommand, aDevice, 0, null);
	}

	public byte deviceState(int idx) {
		return mDeviceState[idx];
	}
	public void setDeviceState(int idx, byte status) {
		mDeviceState[idx] = status;
	}

	public PacketVersion deviceVersion(int idx) {
		return mDeviceVersion[idx];
	}

	public PacketTouchConfig touchConfig() {
		return mTouchConfig;
	}

	public PacketCameraConfig cameraConfig(int idx) {
		return mCameraConfig[idx];
	}

	static {
		System.loadLibrary("jni_usbhid");
	}
	private native int usbhidStart();
	private native void usbhidStop();
	private native int usbhidWrite(int incount, byte[] inarray);
	private static void usbhidCallback(int aStatus, int aCmd, int aDev, int aDlen, byte[] aData) {
		switch (aStatus) {
		case 0:	//LIBUSB_TRANSFER_COMPLETED
			parsePacket(aCmd, aDev, aDlen, aData);
			break;
		case 5:	//LIBUSB_TRANSFER_NO_DEVICE
			android.os.Process.killProcess(android.os.Process.myPid());
			break;
		case 2:	//LIBUSB_TRANSFER_TIMED_OUT
			break;
		case 1:	//LIBUSB_TRANSFER_ERROR
		case 3:	//LIBUSB_TRANSFER_CANCELLED
		case 4:	//LIBUSB_TRANSFER_STALL
		case 6:	//LIBUSB_TRANSFER_OVERFLOW
			log("usbhidCallback(" + aStatus + ")");
			return;
		}
	}

	private static void parsePacket(int aCmd, int aDev, int aDlen, byte[] aData) {
		switch (aCmd) {
		case g.command.RESULT_SUCCESS:
			if (cmdResultSuccess(aDev, aDlen, aData)) {
				mHandler.sendMessage(Message.obtain(mHandler, HANDLER_RESULT, aDev, aDlen, aData));
			}
			break;
		case g.command.RESULT_ERROR:
			log("ERROR : RESULT_ERROR");
			break;
		default:
			if (evtProc(aCmd, aDev, aDlen, aData)) {
				mHandler.sendMessage(Message.obtain(mHandler, HANDLER_EVENT, (aCmd<<16 | aDev), aDlen, aData));
			}
			break;
		}
	}

	private static final int RES_POS_CMD = 0;
	private static final int RES_POS_DATA = 1;
	private static boolean cmdResultSuccess(int aDev, int aDlen, byte[] aData) {
		int dataLen = aDlen - 1;
		int command = (aData[RES_POS_CMD] & 0xFF);
		boolean result = false;

		switch (command) {
		case g.command.PING:
			result = (2 == dataLen) ? true : false;
			if (result) {
				mDeviceState[aDev] = aData[RES_POS_DATA];
				log("BoardAddr(" + aData[RES_POS_DATA+1] + ")");
			}
			break;
		case g.command.RESET:
			result = (1 == dataLen) ? true : false;
			if (result) {
			}
			break;
		case g.command.GET_VERSION:
			result = (PacketData.VERSION_LEN == dataLen) ? true : false;
			if (result) {
				if (null == mDeviceVersion[aDev]) {
					mDeviceVersion[aDev] = new PacketVersion();
				}
				mDeviceVersion[aDev].set(RES_POS_DATA, aData);
			}
			break;
		case g.command.UPGRADE_FWINFO:
			result = (PacketData.FWINFO_LEN == dataLen) ? true : false;
			if (result) {
			}
			break;
		case g.command.UPGRADE_FWDATA:
			result = (PacketData.FWDATA_LEN == dataLen) ? true : false;
			if (result) {
			}
			break;
		case g.command.GET_STATE:
			break;
		case g.command.SET_STATE:
			result = (1 == dataLen) ? true : false;
			if (result) {
				mDeviceState[aDev] = aData[RES_POS_DATA];
			}
			break;
		case g.command.SET_BUZZER:
		case g.command.FORMAT_STORAGE:
			break;

		case g.command.TEST_CODE:
			result = (1 == dataLen) ? true : false;
			if (result) {
			}
			break;

		case g.command.GET_TOUCH_CONFIG:
			result = (PacketData.TOUCH_CONFIG_LEN == dataLen) ? true : false;
			if (result) {
				mTouchConfig.set(RES_POS_DATA, aData);
			}
			break;
		case g.command.SET_TOUCH_CONFIG:
			break;
		case g.command.SET_TOUCH_FILTER:
			result = (1 == dataLen) ? true : false;
			if (result) {
				mTouchConfig.bFilterNum = aData[RES_POS_DATA];
			}
			break;
		case g.command.SET_INPUT_MODE:
			result = (1 == dataLen) ? true : false;
			if (result) {
				mTouchConfig.bInputMode = aData[RES_POS_DATA];
			}
			break;
		case g.command.SET_PWMS:
			result = (g.DATA_PWM_NUM == dataLen) ? true : false;
			if (result) {
				for (int i=0; i<g.DATA_PWM_NUM; i++) {
					mTouchConfig.bPWMs[i] = aData[RES_POS_DATA + i];
				}
			}
			break;
		case g.command.SET_TAP_TIME:
		case g.command.SET_LTAP_TIME:
		case g.command.SET_TAP_AREA:
		case g.command.SET_DTAP_AREA:
		case g.command.SET_PALM_AREA:
			break;
		case g.command.SET_BEEP_ALERT:
			result = (1 == dataLen) ? true : false;
			if (result) {
				mTouchConfig.bBeepAlert = aData[RES_POS_DATA];
			}
			break;
		case g.command.SET_BEEP_CLICK:
			result = (1 == dataLen) ? true : false;
			if (result) {
				mTouchConfig.bBeepClick = aData[RES_POS_DATA];
			}
			break;
		case g.command.SET_TOUCH_NOSEND:
			result = (1 == dataLen) ? true : false;
			if (result) {
				mTouchConfig.bTouchNoSend = aData[RES_POS_DATA];
			}
			break;

		case g.command.GET_CAMERA_CONFIG:
			result = (PacketData.CAMERA_CONFIG_LEN == dataLen) ? true : false;
			if (result) {
				int idx = aDev - g.device.CAMERA1;
				if (null == mCameraConfig[idx]) {
					mCameraConfig[idx] = new PacketCameraConfig();
				}
				mCameraConfig[idx].set(RES_POS_DATA, aData);
			}
			break;
		case g.command.SET_CAMERA_CONFIG:
			break;
		case g.command.SET_YCENTER:
			result = (2 == dataLen) ? true : false;
			if (result) {
				int idx = aDev - g.device.CAMERA1;
				mCameraConfig[idx].nYCenter = (short)PacketData.byteArrayToUshort(RES_POS_DATA, aData);
			}
			break;
		case g.command.SET_XSTART:
			result = (2 == dataLen) ? true : false;
			if (result) {
				int idx = aDev - g.device.CAMERA1;
				mCameraConfig[idx].wXStart = (short)PacketData.byteArrayToUshort(RES_POS_DATA, aData);
			}
			break;
		case g.command.SET_XEND:
			result = (2 == dataLen) ? true : false;
			if (result) {
				int idx = aDev - g.device.CAMERA1;
				mCameraConfig[idx].wXEnd = (short)PacketData.byteArrayToUshort(RES_POS_DATA, aData);
			}
			break;
		case g.command.SET_THRESHOLD:
			result = (1 == dataLen) ? true : false;
			if (result) {
				int idx = aDev - g.device.CAMERA1;
				mCameraConfig[idx].bThreshold = (short)(aData[RES_POS_DATA] & 0xFF);
			}
			break;
		case g.command.SET_MINWIDTH:
			result = (1 == dataLen) ? true : false;
			if (result) {
				int idx = aDev - g.device.CAMERA1;
				mCameraConfig[idx].bMinWidth = (byte)(aData[RES_POS_DATA] & 0xFF);
			}
			break;
		case g.command.SET_AVERAGELIGHT:
			result = (1 == dataLen) ? true : false;
			if (result) {
				int idx = aDev - g.device.CAMERA1;
				mCameraConfig[idx].bAverageLight = (short)(aData[RES_POS_DATA] & 0xFF);
			}
			break;
		case g.command.SET_COEFFS:
			result = (g.DATA_COEFFS_NUM*4 == dataLen) ? true : false;
			if (result) {
				int idx = aDev - g.device.CAMERA1;
				for (int i=0; i<g.DATA_COEFFS_NUM; i++) {
					mCameraConfig[idx].fCoeffs[i] = PacketData.byteArrayToFloat(RES_POS_DATA + i*4, aData);
				}
			}
			break;

		case g.command.SIDEVIEW_START:
			result = (1 == dataLen) ? true : false;
			if (result) {
			}
			break;
		case g.command.DETECTION_START:
		case g.command.CALIBRATION_START:
			break;

		default:
			String strArgs = String.format("%#x, %#x, %#x(%d)", command, aDev, dataLen, dataLen);
			log("Unknown : cmdResultSuccess(" + strArgs + ")");
			return false;
		}

		if (false == result) {
			String strArgs = String.format("%#x, %#x, %#x(%d)", command, aDev, dataLen, dataLen);
			log("ERROR : DATALEN(" + dataLen + "),  " + strArgs);
		}

		return result;
	}


	private static boolean evtProc(int aCmd, int aDev, int aDlen, byte[] aData) {
		boolean result = false;

		switch (aCmd) {
		case g.command.EVT_CAMERA_INIT:
		case g.command.EVT_IMAGE_SIDEVIEW:
		case g.command.EVT_IMAGE_DETECTION:
		case g.command.EVT_RADIAN_DATA:
		case g.command.EVT_LINEEQ_DATA:
			result = true;
			break;
		}

		if (false == result) {
			String strArgs = String.format("%#x, %#x, %#x(%d)", aCmd, aDev, aDlen, aDlen);
			log("ERROR : evtProc(" + strArgs + ")");
		}

		return result;
	}
}
